<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>对象类型的数据监测</title>
</head>
<body>
    <div>
        <div>
            <h2>显示内容</h2>
            <div class="content"></div>
            <div class="content2"></div>
        </div>
    </div>
</body>
</html>

<script>

    this.data = {
        userName: 'jht',
        job: '前端工程师'
    }

    document.getElementsByClassName('content')[0].innerHTML = this.data.userName

    /**
     * 存储依赖的类
     * 依赖其实就是用了这个状态的地方
     * 
     */
    class Dep{
        constructor() {
            this.subs = []
        }

        addSubs(sub) {
            this.subs.push(sub)
        }
        removeSubs(sub) {
            remove(this.subs, sub)
        }
        depend() {
            if(window.target){
                this.addSubs(window.target)   
            }        
        }
        notify() {
            const subs = this.subs.slice()
            console.log('subs:--------->', subs);
            for(let i=0;i<subs.length;i++){
                subs[i].update()
            }
        }
        remove(arr, item) {
            if(arr.length){
                let index = arr.indexOf(item)
                if(index > -1){
                    arr.splice(index,1)
                }
            }
        }
    }

    class Watcher {
        constructor(vm, expOrFn, cb) {
            this.vm = vm
            this.getter = parsePath(expOrFn)
            this.cb = cb
            this.value = this.get()
        }
        get() {
            window.target = this
            let value = this.getter.call(this.vm, this.vm)
            window.target = undefined
            return value
        }

        update() {
            const oldValue = this.value
            this.value = this.get()
            this.cb.call(this.vm, this.value, oldValue)
        }
    }
    

    const bailRE = /[^\w.$]/ // 匹配数字、字母、下划线
    function parsePath(path) {
        if(bailRE.test(path)){
            return
        }
        const segments = path.split('.')
        console.log('segments:', segments);
        return function(obj) {
            for(let i=0;i<segments.length;i++){
                if(!obj) return 
                console.log(`segments[${i}]`, segments[i]);
                obj = obj[segments[i]]
            }
            console.log('obj:', obj);
            return obj
        }
    }


    class Observer {
        constructor(value){
            this.value = value
            if(!Array.isArray(this.value)){
                this.walk(this.value)
            }
        }
        walk(obj) {
            const keys = Object.keys(obj)
            for(let i=0;i<keys.length;i++){
                this.defineReactive(obj, keys[i], obj[keys[i]]) 
            }
        }

        /**
         * 定义响应式数据
        */
        defineReactive(data, key, val) {
            if(typeof val === 'object') {
                new Observer(val)
            }
            let dep = new Dep()
            Object.defineProperty(data, key, {
                enumerable: true,
                configurable: true,
                get: function() {
                    // 收集依赖
                    dep.depend()
                    return val
                },
                set: function(newVal) {
                    // 更新依赖
                    if(val === newVal){
                        return
                    }
                    val = newVal
                    dep.notify()
                }
            })
        }
    }
    new Observer(this.data)
    let watch = new Watcher(this, 'data.userName', (newValue,oldValue) => {
        console.log('newValue:', newValue);
        console.log('oldValue:', oldValue);
        document.getElementsByClassName('content')[0].innerHTML = newValue
    })
    this.data.userName = '蒋皓天'
    this.data.userName = '周钰'

    console.log('Array:', new Array());
    class JhtArray {
        constructor() {
            return [1,2,3,4]
        }
    }
    window.jhtArr = new JhtArray()
</script>